<?php

namespace App\Services\Passport;

use GuzzleHttp\Client as Http;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
use Illuminate\Support\Arr;
use Log;

class Client
{

    protected $grant;

    protected $app;

    public function __construct($app, array $config = [])
    {
        $this->app    = $app;
        $this->config = $config;

        $this->setGrant($this->config['grant']);
    }

    /**
     *  注册通行证
     *  可以密码注册或者短信注册
     *  短信注册需先调用短信发送接口
     */
    public function register(array $user)
    {
        return $this->withErrorHandling(function() use ($user){

            $response = $this->request('post', '/api/register', $user);

            $response = $this->parseResponse($response);

            return (new UserProvider($this->app))->syncByResponse( (array)$response );
        });
    }

    public function login(array $credentials)
    {
        return $this->withErrorHandling(function() use($credentials){

            $response = $this->request('post', '/api/login', $credentials);

            $response = $this->parseResponse($response);

            $res = (new UserProvider($this->app))->retrieveByCredentials( Arr::only((array)$response, ['phone']));
            if ( !$res ){
                return (new UserProvider($this->app))->syncByResponse( (array)$response );
            }
            return $res;
        });
        
    }

    public function passwordReset(array $reset)
    {
        return $this->withErrorHandling(function() use($reset){

            $response = $this->request('post', '/api/password/reset', $reset);

            return $this->parseResponse($response);
        });
    }

    public function sendSMS($phone)
    {
        return $this->withErrorHandling(function() use($phone){

            $response = $this->request('post', '/api/sms/send', [
                'phone' => $phone,
            ]);

            return $this->parseResponse($response);
        });
    }

    protected function withErrorHandling($callback)
    {
        try{
            return $callback();
        }catch(ClientException $e){
            $response = $e->getResponse()->getBody();
            $response = json_decode($response);
            throw new \Exception($response->message);
        }catch(ServerException $e){
            $response = $e->getResponse()->getBody();
            $response = json_decode($response);
            throw new \Exception($response->message);
        }
    }

    protected function params($grant, $base_uri)
    {
        return [
            'clientId'                => $grant['client_id'],    // The client ID assigned to you by the provider
            'clientSecret'            => $grant['client_secret'],    // The client password assigned to you by the provider
            'redirectUri'             => $grant['redirect_uri'],
            'urlAuthorize'            => $base_uri.'/oauth/authorize',
            'urlAccessToken'          => $base_uri.'/oauth/token',
            'urlResourceOwnerDetails' => $base_uri.'/oauth/resource',
        ];
    }

    protected function setGrant($grant)
    {
        $this->grant = $grant;
    }

    protected function request($method, $url, $options)
    {
        $http = new Http([
            'base_uri' => $this->config['base_uri'],
            'verify' => false
        ]);
        print_r($this->config['base_uri']);exit;
        return $http->request($method, $url, [
            'headers' => $this->getHeaders(),
            'form_params' => $options,
        ]);
    }

    protected function getHeaders()
    {
        $grant = $this->grant;
        $base_uri = $this->config['base_uri'];
        
        $accessToken = new AccessToken($grant, $this->params($this->config[$grant], $base_uri));
        
        return [
            'Version' => 'v1',
            'Authorization' => "Bearer ". $accessToken,
            'Accept'  => 'application/json'
        ];
    }

    protected function parseResponse($stream)
    {
        if ( $stream->getStatusCode() !== 200 ){
            throw new \Exception('请求失败');
        }

        $response = $stream->getBody();
        if ( !$response ){
            throw new \Exception('请求失败');
        }

        $result = json_decode((string)$response);
        if ( isset($result->error_code) ){
            if ( $result->error_code ){
                throw new \Exception($result->error_msg);
            }
            return true;
        }

        return $result ?: true;
    }

}